package com.deman.framework.rpc.config;

import com.deman.framework.rpc.properties.RpcSystemConfigProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.*;

public class DemanRpcImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    Logger logger= LoggerFactory.getLogger(DemanRpcImportBeanDefinitionRegistrar.class);
    private ResourceLoader resourceLoader;
    private Environment environment;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {

        Set <String> packages = getBasePackages(metadata);
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(resourceLoader);
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(DemanRpcClient.class);
        scanner.addIncludeFilter(annotationTypeFilter);

        packages.forEach(basePackage -> {
            Set <BeanDefinition> beanDefinitions = scanner.findCandidateComponents(basePackage);
            beanDefinitions.forEach(bean -> {
                logger.debug("beanName[{}]",bean.getBeanClassName());
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DemanRpcReferrenceFactoryBean.class);
                beanDefinitionBuilder.addPropertyValue("interfaceName", bean.getBeanClassName());
                beanDefinitionBuilder.addPropertyValue("serviceName", bean.getBeanClassName());
                beanDefinitionBuilder.setLazyInit(true);
                beanDefinitionBuilder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
                AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
                beanDefinition.setPrimary(true);
                registry.registerBeanDefinition(bean.getBeanClassName() + "RpcClient", beanDefinition);
            });

        });


    }

    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

    protected Set <String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        Map <String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableDemanRpcClients.class.getCanonicalName());
        Set <String> basePackages = new HashSet <>();

        for (String pkg : (String[]) attributes.get("basePackages")) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        if (basePackages.isEmpty()) {
            basePackages.add(
                    ClassUtils.getPackageName(importingClassMetadata.getClassName()));
        }
        return basePackages;
    }

//
//    private static class AllTypeFilter implements TypeFilter {
//
//        private final List <TypeFilter> delegates;
//
//        /**
//         * Creates a new {@link AllTypeFilter} to match if all the given delegates match.
//         *
//         * @param delegates must not be {@literal null}.
//         */
//        public AllTypeFilter(List <TypeFilter> delegates) {
//            Assert.notNull(delegates, "This argument is required, it must not be null");
//            this.delegates = delegates;
//        }
//
//        @Override
//        public boolean match(MetadataReader metadataReader,
//                             MetadataReaderFactory metadataReaderFactory) throws IOException {
//
//            for (TypeFilter filter : this.delegates) {
//                if (!filter.match(metadataReader, metadataReaderFactory)) {
//                    return false;
//                }
//            }
//
//            return true;
//        }
//    }
}

